﻿using AntdUI;
using Markdig;
using Microsoft.Web.WebView2.Core;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using WorkTool2.Helpers;

namespace WorkTool2;

public partial class MarkdownForm : Window
{
    private const string FILE_PREFIX = "attachment:";
    private const string HOST_NAME = "local.example";
    private string _resourcesFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ToolHelper.MARKDOWN_FOLDER, ToolHelper.MARKDOWN_FILES_FOLDER);

    private readonly System.Windows.Forms.Timer updateTimer;
    private CancellationTokenSource _updateCancellation;

    private static readonly Dictionary<string, string> _imageDic = new() {
        { ".png", "image/png" },
        { ".jpg", "image/jpeg" },
        { ".jpeg", "image/jpeg" },
        { ".gif", "image/gif" },
        { ".bmp", "image/bmp" },
        { ".svg", "image/svg+xml" },
        { ".webp", "image/webp" },
        { ".ico", "image/x-icon" },
    };

    private bool _isWebViewInitialized = false;
    private string currentHtml = "";
    private string _lastProcessedHtml = "";

    public MarkdownForm()
    {
        InitializeComponent();
        windowBar.Text += " " + $"[{Application.ProductVersion}]";
        Tag = Guid.NewGuid().ToString("N");
        // 设置预览更新定时器
        updateTimer = new System.Windows.Forms.Timer
        {
            Interval = 800 // 增加延迟减少频繁更新
        };
        updateTimer.Tick += updateTimer_Tick;
        InitializeWebView2Async();
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        ActiveControl = textBox_markdown;
        ITask.Run(() =>
        {
            menu.Items.Add(new MenuItem("导出", "").SetTag("export")
                .SetSub(
                new MenuItem("Markdown").SetTag("exportMarkdown"),
                new MenuItem("HTML").SetTag("exportHTML"),
                new MenuItem("PDF").SetTag("exportPDF")
                //new MenuItem("Image").SetTag("exportImage")
                )
            );

            menu.Items.Add(new MenuItem("粗体", "").SetTag("bold"));
            menu.Items.Add(new MenuItem("斜体", "").SetTag("italic"));
            menu.Items.Add(new MenuItem("H1", "").SetTag("h1"));
            menu.Items.Add(new MenuItem("H2", "").SetTag("h2"));
            menu.Items.Add(new MenuItem("H3", "").SetTag("h3"));
            menu.Items.Add(new MenuItem("分隔线", "").SetTag("horizontalRule"));
            menu.Items.Add(new MenuItem("删除线", "").SetTag("strikethrough"));
            menu.Items.Add(new MenuItem("下划线", "").SetTag("underline"));
            menu.Items.Add(new MenuItem("高亮", "").SetTag("highlight"));

            menu.Items.Add(new MenuItem("代码", "").SetTag("code"));
            menu.Items.Add(new MenuItem("代码块", "").SetTag("codeBlock"));

            menu.Items.Add(new MenuItem("表格", "").SetTag("table"));
            menu.Items.Add(new MenuItem("有序列表", "").SetTag("orderedList"));
            menu.Items.Add(new MenuItem("无序列表", "").SetTag("unorderedList"));
            menu.Items.Add(new MenuItem("任务列表", "").SetTag("taskList"));
            menu.Items.Add(new MenuItem("定义列表", "").SetTag("definitionList"));
            menu.Items.Add(new MenuItem("脚注", "").SetTag("footnote"));

            menu.Items.Add(new MenuItem("链接", "").SetTag("link"));
            menu.Items.Add(new MenuItem("图片", "").SetTag("image"));
            menu.Items.Add(new MenuItem("插入文件", "").SetTag("files"));

            menu.Items.Add(new MenuItem("其他", "").SetTag("other")
                .SetSub(
                new MenuItem("本地文件路径转换").SetTag("localFiles")
                )
            );

            OpenFloatButton();
        });
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        base.OnFormClosing(e);

        if (previewBrowser != null && !previewBrowser.IsDisposed)
        {
            previewBrowser.Dispose();
        }

        // 停止定时器
        if (updateTimer != null)
        {
            updateTimer.Stop();
            updateTimer.Dispose();
        }

        CloseFloatButton();
    }

    /// <summary>
    /// 初始化WebView2
    /// </summary>
    private async void InitializeWebView2Async()
    {
        try
        {
            var env = await CoreWebView2Environment.CreateAsync();// 初始化WebView2环境
            await previewBrowser.EnsureCoreWebView2Async(env);
            // 启用本地文件访问
            previewBrowser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = true;
            previewBrowser.CoreWebView2.Settings.IsWebMessageEnabled = true;
            _isWebViewInitialized = true;// 设置初始化完成标志
            UpdatePreview();// 初始更新预览
        }
        catch (Exception ex)
        {
            MessageBox.Show($"WebView2初始化失败: {ex.Message}\n请确保已安装WebView2运行时。\nhttps://developer.microsoft.com/en-us/microsoft-edge/webview2/");
        }
    }

    /// <summary>
    /// 添加菜单
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void menu_ItemClick(object sender, MenuItemEventArgs e)
    {
        var tag = e.Item.Tag as string;
        switch (tag)
        {
            case "bold":
                InsertMarkdown("**", "**");
                break;

            case "italic":
                InsertMarkdown("*", "*");
                break;

            case "h1":
                InsertMarkdown("# ", "");
                break;

            case "h2":
                InsertMarkdown("## ", "");
                break;

            case "h3":
                InsertMarkdown("### ", "");
                break;

            case "horizontalRule":
                InsertMarkdown(@"
---", "\n", 1);
                break;

            case "strikethrough":
                InsertMarkdown("~~", "~~");
                break;

            case "underline":
                InsertMarkdown("<u>", "</u>");
                break;

            case "highlight":
                InsertMarkdown("==", "==");
                break;

            case "code":
                InsertMarkdown("`", "`");
                break;

            case "codeBlock":
                InsertMarkdown("```", "```");
                break;

            case "table":
            case "orderedList":
            case "unorderedList":
            case "taskList":
            case "definitionList":
            case "footnote":
                InsertMarkdown(tag);
                break;

            case "link":
                InsertMarkdown("[", "](url \"\")", 2, 3);
                break;

            case "image":
                InsertMarkdown("![", "](url \"\")", 2, 3);
                break;

            case "files":
                {
                    using var openFileDialog = new OpenFileDialog
                    {
                        Title = "选择文件",
                        Filter = "所有文件|*.*",
                        Multiselect = true,
                        InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
                    };
                    if (openFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        InsertFilesMarkdown(openFileDialog.FileNames);
                    }
                }
                break;

            case "localFiles":
                ExtractAndConvertFilePaths(textBox_markdown.Text);
                break;

            case "exportMarkdown":
                await SaveMarkdown(textBox_markdown.Text, "Markdown文件 (*.md)|*.md", ".md");
                break;

            case "exportHTML":
                await SaveMarkdown(currentHtml, "HTML Files|*.html", ".html");
                break;

            case "exportPDF":
                await SaveMarkdown(currentHtml, "HTML Files|*.pdf", ".pdf");
                break;

            default:
                break;
        }
        menu.USelect();
    }

    /// <summary>
    /// 完整的Markdown和附件保存流程
    /// </summary>
    /// <param name="markdownContent">要保存的Markdown内容</param>
    /// <param name="filter">文件过滤</param>
    /// <param name="extension">文件后缀</param>
    /// <returns>是否成功保存</returns>
    public async Task<bool> SaveMarkdown(string markdownContent, string filter, string extension)
    {
        try
        {
            var attachments = ExtractAttachmentReferences();
            filter = extension.Equals(".pdf") ? filter : (attachments.Count > 0 ? "所有文件 (*.*)|*.*" : filter);
            using var saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = filter;
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.RestoreDirectory = true;
            saveFileDialog.Title = "另存为";
            saveFileDialog.FileName = Tag.ToString();
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                var filePath = saveFileDialog.FileName;
                if (!string.IsNullOrEmpty(filePath))
                {
                    if (extension.Equals(".pdf"))
                    {
                        await previewBrowser.InvokeIfRequiredAsync(async () =>
                        {
                            var printSettings = previewBrowser.CoreWebView2.Environment.CreatePrintSettings();

                            // 使用横向布局获得更多宽度空间
                            printSettings.Orientation = CoreWebView2PrintOrientation.Landscape;
                            printSettings.PageWidth = 11;
                            printSettings.PageHeight = 8.5;

                            // 最小化边距
                            printSettings.MarginTop = 0.2;
                            printSettings.MarginBottom = 0.2;
                            printSettings.MarginLeft = 0.2;
                            printSettings.MarginRight = 0.2;

                            // 适当缩放
                            printSettings.ScaleFactor = 0.9;
                            printSettings.ShouldPrintBackgrounds = true;
                            await previewBrowser.CoreWebView2.PrintToPdfAsync(filePath, printSettings);
                        });
                    }
                    else
                    {
                        if (attachments.Count > 0)
                        {
                            if (!Directory.Exists(filePath))
                                Directory.CreateDirectory(filePath);
                            foreach (var attachment in attachments)
                            {
                                File.Copy(Path.Combine(_resourcesFolder, $"{attachment}"), Path.Combine(filePath, $"{attachment}"), true);
                            }
                            File.WriteAllText(Path.Combine(filePath, Path.GetFileName(filePath) + extension), markdownContent, Encoding.UTF8);
                        }
                        else
                        {
                            File.WriteAllText(filePath, markdownContent, Encoding.UTF8);
                        }
                    }
                    var startInfo = new ProcessStartInfo();

                    if (Directory.Exists(filePath))
                    {
                        startInfo.FileName = "explorer.exe";
                        startInfo.Arguments = $"\"{filePath}\"";
                    }
                    else
                    {
                        startInfo.FileName = $"\"{filePath}\"";
                        startInfo.UseShellExecute = true;
                    }
                    using var process = Process.Start(startInfo);
                    return process != null;
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            // 处理异常
            MessageBox.Show($"保存过程中发生错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return false;
        }
    }

    /// <summary>
    /// 从Markdown内容中提取所有附件引用
    /// </summary>
    /// <returns>附件路径列表</returns>
    private List<string> ExtractAttachmentReferences()
    {
        var markdownContent = textBox_markdown.Text;
        var attachments = new List<string>();

        // 匹配Markdown格式的图片和链接
        var mdRegex = new Regex(@"(?:!?\[[^\]]*\]\()(attachment:[0-9a-fA-F]{32}(?:\.[0-9a-zA-Z]{0,10})?)(?:[^)]*\))", RegexOptions.IgnoreCase);
        var matches = mdRegex.Matches(markdownContent);

        foreach (Match match in matches)
        {
            if (match.Groups.Count > 1 && !string.IsNullOrEmpty(match.Groups[1].Value))
            {
                string attachmentPath = match.Groups[1].Value.Replace(FILE_PREFIX, "");
                if (!attachments.Contains(attachmentPath))
                {
                    attachments.Add(attachmentPath);
                }
            }
        }

        // 匹配HTML格式的图片和链接
        var htmlRegex = new Regex(@"<(?:img|a)[^>]+(?:src|href)=([""'])(attachment:[0-9a-fA-F]{32}(?:\.[0-9a-zA-Z]{0,10})?)\1[^>]*>", RegexOptions.IgnoreCase);
        var htmlMatches = htmlRegex.Matches(markdownContent);

        foreach (Match match in htmlMatches)
        {
            if (match.Groups.Count > 2 && !string.IsNullOrEmpty(match.Groups[2].Value))
            {
                string attachmentPath = match.Groups[2].Value.Replace(FILE_PREFIX, "");
                if (!attachments.Contains(attachmentPath))
                {
                    attachments.Add(attachmentPath);
                }
            }
        }

        return attachments;
    }

    private void updateTimer_Tick(object? sender, EventArgs e)
    {
        updateTimer.Stop();
        UpdatePreview();
    }

    /// <summary>
    /// 文本框内容变更
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void textBox_markdown_TextChanged(object sender, EventArgs e)
    {
        updateTimer.Stop();
        updateTimer.Start();
    }

    /// <summary>
    /// 拖拽进入文本框时的事件处理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void textBox_markdown_DragEnter(object? sender, DragEventArgs e)
    {
        e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None;// 检查拖拽的数据是否包含文件
    }

    /// <summary>
    /// 拖拽放置到文本框时的事件处理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void textBox_markdown_DragDrop(object? sender, DragEventArgs e)
    {
        string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
        if (files.Any(x => string.IsNullOrEmpty(Path.GetExtension(x))))
        {
            AntdUI.Modal.open(new Modal.Config(this, "错误", "不能拖入文件夹", TType.Error)
            {
                CancelText = null,
                OkType = TTypeMini.Error,
                OkText = "知道了"
            });
        }
        else
        {
            InsertFilesMarkdown(files);
        }
    }

    /// <summary>
    /// 文本框Ctrl+V
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void textBox_markdown_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.V)
        {
            // 检查剪贴板中是否有文件
            if (Clipboard.ContainsFileDropList())
            {
                var files = Clipboard.GetFileDropList().Cast<string>().ToArray();
                InsertFilesMarkdown(files);
            }
        }
    }

    private void InsertMarkdown(string prefix, string suffix, int startLength = 0, int length = 0)
    {
        int selectionStart = textBox_markdown.SelectionStart;
        var selectedTextLength = 0;
        if (textBox_markdown.SelectionLength > 0)
        {
            var selectedText = textBox_markdown.SelectedText;
            selectedTextLength = selectedText.Length;
            textBox_markdown.SelectedText = $"{prefix}{selectedText}{suffix}";
        }
        else
        {
            textBox_markdown.Text = textBox_markdown.Text.Insert(selectionStart, $"{prefix}{suffix}");
        }
        textBox_markdown.Select(selectionStart + prefix.Length + selectedTextLength + startLength, length);
        textBox_markdown.Focus();
    }

    private void InsertMarkdown(string insertType)
    {
        var insert = "\n\n\r";
        switch (insertType)
        {
            case "table":
                insert += @"
| 表头1 | 表头2 | 表头3 |
|-|-|-|
| 内容1 | 内容2 | 内容3 |
| 内容4 | 内容5 | 内容6 |";
                break;

            case "orderedList":
                insert += @"
1. First item
2. Second item
3. Third item";
                break;

            case "unorderedList":
                insert += @"
- First item
- Second item
- Third item";
                break;

            case "taskList":
                insert += @"
- [x] Write the press release
- [ ] Update the website
- [ ] Contact the media";
                break;

            case "definitionList":
                insert += @"
<dl>
  <dt>First Term</dt>
  <dd>This is the definition of the first term.</dd>
  <dt>Second Term</dt>
  <dd>This is one definition of the second term. </dd>
  <dd>This is another definition of the second term.</dd>
</dl>";
                break;

            case "footnote":
                insert += @"
Here's a sentence with a footnote. [^1]
[^1]: This is the footnote.";
                break;

            default:
                break;
        }
        var selectionStart = textBox_markdown.SelectionStart;
        textBox_markdown.Text = textBox_markdown.Text.Insert(selectionStart, insert);
        textBox_markdown.SelectionStart = selectionStart + 5;
        textBox_markdown.Focus();
    }

    private void InsertFilesMarkdown(string[] files)
    {
        if (files != null && files.Length > 0)
        {
            foreach (string file in files)
            {
                if (File.Exists(file))
                {
                    var fileId = Guid.NewGuid().ToString("N");
                    var fileName = Path.GetFileName(file);
                    var extension = Path.GetExtension(fileName);
                    var nameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
                    var destFilePath = Path.Combine(_resourcesFolder, $"{fileId}{extension}");
                    // 复制文件到资源文件夹
                    File.Copy(file, destFilePath, true);
                    string? prefix;
                    string? suffix;
                    if (IsImageFile(file))
                    {
                        prefix = "![";
                        suffix = $"{fileName}]({FILE_PREFIX}{fileId}{extension} \"{nameWithoutExt}\")";
                    }
                    else
                    {
                        prefix = "[";
                        suffix = $"{nameWithoutExt}]({FILE_PREFIX}{fileId}{extension} \"{fileName}\")";
                    }
                    InsertMarkdown(prefix, suffix, prefix.Length + suffix.Length, 0);
                }
            }
        }
    }

    private async void UpdatePreview()
    {
        if (previewBrowser == null || !_isWebViewInitialized)
            return;
        // 取消之前的更新任务
        _updateCancellation?.Cancel();
        _updateCancellation = new CancellationTokenSource();
        var cancellationToken = _updateCancellation.Token;
        try
        {
            // 使用Markdig将Markdown转换为HTML，启用所有扩展
            var markdown = textBox_markdown.Text;

            // 在后台线程处理Markdown转换和图片处理
            var html = await Task.Run(() =>
            {
                if (cancellationToken.IsCancellationRequested)
                    return string.Empty;

                // 创建支持所有常用扩展的Markdown管道
                var pipeline = new MarkdownPipelineBuilder()
                    .UseAdvancedExtensions() // 启用高级扩展
                    .UseEmphasisExtras()     // 启用额外强调功能（包括删除线）
                    .UseGridTables()         // 启用网格表格支持
                    .UsePipeTables()         // 启用管道表格支持
                    .UseEmojiAndSmiley()     // 启用表情符号短码支持
                    .UseDefinitionLists()    // 启用定义列表支持
                    .Build();

                var result = Markdown.ToHtml(markdown, pipeline);

                // 处理HTML实体编码 - 将&quot;等转换回实际字符
                result = System.Net.WebUtility.HtmlDecode(result);

                // 只有当HTML内容实际发生变化时才更新
                if (result == _lastProcessedHtml)
                    return null;

                _lastProcessedHtml = result;

                // 只在需要时处理图片
                if (result.Contains("<img "))
                {
                    result = ProcessHtmlImageTags(result);
                }
                // 只在需要时处理图片
                if (result.Contains("<a "))
                {
                    result = ProcessHtmlAnchorTagsEnhanced(result);
                }

                return result;
            }, cancellationToken);

            if (cancellationToken.IsCancellationRequested || html == null)
                return;

            // 添加CSS样式和JS功能
            var styledHtml = _styledHtmlTemplate.Replace("#CONTENT#", html);

            // 更新预览
            currentHtml = styledHtml.Replace("#HOSTNAME#", "");

            previewBrowser.InvokeIfRequired(() =>
            {
                previewBrowser.CoreWebView2.SetVirtualHostNameToFolderMapping(
                    HOST_NAME,  // 虚拟主机名
                    _resourcesFolder,      // 本地文件夹路径
                    CoreWebView2HostResourceAccessKind.Allow);  // 允许访问
                if (!cancellationToken.IsCancellationRequested)
                    previewBrowser.NavigateToString(styledHtml.Replace("#HOSTNAME#", "<base href='http://local.example/' />"));
            });
        }
        catch (OperationCanceledException)
        {
            // 更新被取消，忽略异常
        }
    }

    #region 悬浮按钮

    private AntdUI.FormFloatButton FloatButton = null;

    private void OpenFloatButton()
    {
        FloatButton ??= AntdUI.FloatButton.open(new FloatButton.Config(this, [
                new FloatButton.ConfigBtn("new").SetIcon("FileAddOutlined").SetTooltip("新建"),
                new FloatButton.ConfigBtn("open").SetIcon("FileMarkdownOutlined").SetTooltip("打开"),
                new FloatButton.ConfigBtn("markdown").SetIcon("ReadOutlined").SetTooltip("Markdown教程"),
            ], btn =>
            {
                switch (btn.Name)
                {
                    case "new":
                        var newForm = (Form)Activator.CreateInstance(this.GetType());
                        newForm.Show();
                        break;

                    case "open":
                        {
                            using var ofd = new OpenFileDialog();
                            ofd.Filter = "Markdown Files|*.md|Text Files|*.txt|All Files|*.*";
                            if (ofd.ShowDialog() == DialogResult.OK)
                            {
                                _resourcesFolder = Path.GetDirectoryName(ofd.FileName);
                                textBox_markdown.Text = File.ReadAllText(ofd.FileName);
                            }
                        }
                        break;

                    case "markdown":
                        previewBrowser.CoreWebView2.Navigate("https://markdown.com.cn/cheat-sheet.html");
                        break;

                    default:
                        break;
                }
            }));
    }

    private void CloseFloatButton()
    {
        if (FloatButton != null)
        {
            FloatButton.Close();
            FloatButton = null;
        }
    }

    #endregion

    /// <summary>
    /// 处理HTML格式的图片标签
    /// </summary>
    /// <param name="html">HTML内容</param>
    /// <returns>处理后的HTML内容</returns>
    private string ProcessHtmlImageTags(string html)
    {
        var htmlImgRegex = new Regex("<img[^>]+src=([\"'])([^>]*?)\\1[^>]*>", RegexOptions.IgnoreCase);// 正则表达式匹配HTML img标签
        return htmlImgRegex.Replace(html, match =>
        {
            var src = match.Groups[2].Value;
            if (src.StartsWith(FILE_PREFIX))
            {
                var file = src.Replace(FILE_PREFIX, "");
                return match.Value.Replace($"\"{src}\"", $"\"./{file}\"");
            }
            return match.Value;// 对于非本地图片或网络图片，保持不变
        });
    }

    /// <summary>
    /// 处理HTML格式的A标签（超链接）
    /// </summary>
    /// <param name="html">HTML内容</param>
    /// <returns>处理后的HTML内容</returns>
    private string ProcessHtmlAnchorTagsEnhanced(string html)
    {
        // 更精确的正则表达式，匹配完整的a标签
        var htmlAnchorRegex = new Regex("<a\\s+([^>]*?\\s+)?href=([\"'])([^>]*?)\\2([^>]*)>", RegexOptions.IgnoreCase);
        return htmlAnchorRegex.Replace(html, match =>
        {
            var href = match.Groups[3].Value; // href值在第3个分组

            // 检查是否是本地文件路径
            if (href.StartsWith(FILE_PREFIX))
            {
                var file = href.Replace(FILE_PREFIX, "");
                // 替换整个匹配中的href部分
                string beforeHref = match.Value[..(match.Groups[3].Index - match.Index)];
                string afterHref = match.Value[(match.Groups[3].Index - match.Index + match.Groups[3].Length)..];
                return beforeHref + $"./{file}" + afterHref;
            }
            return match.Value;// 对于外部链接，保持不变
        });
    }

    /// <summary>
    /// 检查文件是否为图片
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    private static bool IsImageFile(string filePath)
    {
        var extension = Path.GetExtension(filePath).ToLower();
        return _imageDic.ContainsKey(extension);
    }

    private static readonly Regex MarkdownUrlRegex = new(
        @"(!?)\[(.*?)\]\(\s*((?:[^)\s]|\s(?!\s*[""']))+)\s*(?:\s+[""']([^""']*)[""'])?\s*\)",
        RegexOptions.Compiled | RegexOptions.IgnoreCase
    );

    /// <summary>
    /// 提取本地文件路径并转换为绝对路径
    /// </summary>
    /// <param name="markdownText">Markdown 文本</param>
    /// <param name="baseDirectory">基目录（用于相对路径转换）</param>
    /// <returns></returns>
    public void ExtractAndConvertFilePaths(string markdownText, string baseDirectory = null)
    {
        var results = new List<MarkdownUrl>();

        var matches = MarkdownUrlRegex.Matches(markdownText);
        foreach (Match match in matches)
        {
            if (match.Success && match.Groups.Count >= 4)
            {
                var isImage = match.Groups[1].Value == "!";
                var originalUrl = match.Groups[3].Value.Trim();
                var altText = match.Groups.Count > 4 ? match.Groups[4].Value : string.Empty;
                try
                {
                    if (IsLikelyValidLocalPath(originalUrl))
                    {
                        // 转换为绝对路径
                        var absoluteUrl = ConvertToAbsolutePath(originalUrl, baseDirectory);
                        results.Add(new MarkdownUrl
                        {
                            FullMatch = match.Value,
                            IsImage = isImage,
                            Url = absoluteUrl, // 使用转换后的绝对路径
                            OriginalUrl = originalUrl, // 保留原始路径
                            AltText = altText,
                            StartIndex = match.Index,
                            Length = match.Length,
                            IsAbsolute = Path.IsPathRooted(originalUrl)
                        });
                    }
                }
                catch
                {
                }
            }
        }

        var replaceText = markdownText;
        foreach (var groupItem in results.GroupBy(x => x.Url))
        {
            if (File.Exists(groupItem.Key))
            {
                var fileId = Guid.NewGuid().ToString("N");
                var fileName = Path.GetFileName(groupItem.Key);
                var extension = Path.GetExtension(fileName);
                var nameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
                var destFilePath = Path.Combine(_resourcesFolder, $"{fileId}{extension}");
                File.Copy(groupItem.Key, destFilePath, true);
                foreach (var item in groupItem)
                {
                    replaceText = replaceText.Replace(item.OriginalUrl, FILE_PREFIX + fileId + extension);
                }
            }
        }
        textBox_markdown.InvokeIfRequired(() =>
        {
            textBox_markdown.Text = replaceText;
        });
    }

    private static string ConvertToAbsolutePath(string path, string baseDirectory)
    {
        if (string.IsNullOrEmpty(path))
            return path;

        // 如果已经是绝对路径，直接返回
        if (Path.IsPathRooted(path))
            return Path.GetFullPath(path);

        // 如果有指定的基目录，基于该目录转换
        if (!string.IsNullOrEmpty(baseDirectory))
        {
            var absoluteBase = Path.GetFullPath(baseDirectory);
            return Path.GetFullPath(Path.Combine(absoluteBase, path));
        }

        // 否则基于当前工作目录转换
        return Path.GetFullPath(path);
    }

    private static bool IsLikelyValidLocalPath(string url)
    {
        if (IsClearlyNetworkUrl(url))
            return false;

        if (!LooksLikeLocalPath(url))
            return false;

        return HasValidPathComponents(url);
    }

    /// <summary>
    /// 快速排除网络 URL
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    private static bool IsClearlyNetworkUrl(string url)
    {
        var lowerUrl = url.ToLowerInvariant();
        return lowerUrl.StartsWith("http://") ||
               lowerUrl.StartsWith("https://") ||
               lowerUrl.StartsWith("ftp://") ||
               lowerUrl.StartsWith("www.") ||
               lowerUrl.StartsWith("//") ||
               lowerUrl.Contains("://");
    }

    /// <summary>
    /// 检查路径模式
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private static bool LooksLikeLocalPath(string path)
    {
        // Windows 绝对路径
        if (Regex.IsMatch(path, @"^[a-zA-Z]:\\"))
            return true;

        // Windows 网络路径
        if (path.StartsWith(@"\\"))
            return true;

        // 相对路径
        if (Regex.IsMatch(path, @"^\.{1,2}[/\\]"))
            return true;

        // Unix 绝对路径
        return path.StartsWith("/") && !path.StartsWith("//");
    }

    /// <summary>
    /// 验证路径组件
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private static bool HasValidPathComponents(string path)
    {
        try
        {
            // 检查路径中是否包含非法字符
            if (path.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
                return false;
            // 获取文件名并检查
            var fileName = Path.GetFileName(path);
            if (!string.IsNullOrEmpty(fileName) && fileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
                return false;
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// markdown html 样式
    /// </summary>
    private static readonly string _styledHtmlTemplate = @"
<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    #HOSTNAME#
    <!-- GitHub Markdown CSS -->
    <link rel='stylesheet'
        href='https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown.min.css'>
    <!-- Highlight.js 代码高亮 -->
    <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/github-dark.min.css'>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js'></script>
    <!-- 数学公式支持 -->
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.0/es5/tex-mml-chtml.js'></script>
    <!-- 图表支持 -->
    <!-- <script src='https://cdn.jsdelivr.net/npm/mermaid@9.3.0/dist/mermaid.min.js'></script> -->
    <!-- Twemoji (Twitter的Emoji库) -->
    <script src='https://twemoji.maxcdn.com/v/latest/twemoji.min.js' crossorigin='anonymous'></script>
    <style>
        .markdown-body {
            box-sizing: border-box;
            min-width: 200px;
            max-width: 980px;
            margin: 0 auto;
            padding: 45px;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
        }

        @media (max-width: 767px) {
            .markdown-body {
                padding: 15px;
            }
        }

        /* 自定义额外样式 */
        .markdown-body pre {
            background-color: #f6f8fa;
            border-radius: 6px;
            padding: 16px;
        }

        .markdown-body code {
            background-color: rgba(175, 184, 193, 0.2);
            border-radius: 6px;
            padding: 0.2em 0.4em;
            font-size: 85%;
        }

        /* 表格样式 */
        .markdown-body table {
            border-spacing: 0;
            border-collapse: collapse;
            display: block;
            width: 100%;
            overflow: auto;
            margin-bottom: 16px;
        }

        .markdown-body th,
        .markdown-body td {
            padding: 6px 13px;
            border: 1px solid #d0d7de;
        }

        .markdown-body th {
            font-weight: 600;
            background-color: #f6f8fa;
        }

        .markdown-body tr:nth-child(2n) {
            background-color: #f6f8fa;
        }

        .markdown-body blockquote {
            padding: 0 1em;
            color: #57606a;
            border-left: 0.25em solid #d0d7de;
            margin: 0;
        }

        .markdown-body img {
            max-width: 100%;
            box-sizing: content-box;
            background-color: #ffffff;
        }

        .markdown-body .math-display {
            text-align: center;
            margin: 1em 0;
        }

        /* 删除线样式 */
        .markdown-body del {
            text-decoration: line-through;
            color: #656d76;
        }

        /* 任务列表样式 */
        .markdown-body .task-list-item {
            list-style-type: none;
        }

        .markdown-body .task-list-item-checkbox {
            margin: 0 0.2em 0.25em -1.6em;
            vertical-align: middle;
        }

        /* 脚注样式 */
        .markdown-body .footnotes {
            font-size: 12px;
            color: #656d76;
            border-top: 1px solid #d0d7de;
        }

        /* 定义列表样式 */
        .markdown-body dl {
            padding: 0;
        }

        .markdown-body dl dt {
            padding: 0;
            margin-top: 16px;
            font-size: 1em;
            font-style: italic;
            font-weight: 600;
        }

        .markdown-body dl dd {
            padding: 0 16px;
            margin-bottom: 16px;
        }

        /* Twemoji 样式 */
        .twemoji {
            height: 1em;
            width: 1em;
            margin: 0 .05em 0 .1em;
            vertical-align: -0.1em;
        }

        /* 定义列表样式 */
        .markdown-body dl {
            padding: 0;
        }

        .markdown-body dt {
            font-weight: 600;
            margin-top: 16px;
            padding: 0;
        }

        .markdown-body dd {
            padding: 0 16px;
            margin-bottom: 16px;
            margin-left: 0;
        }

        .markdown-body dd:before {
            content: "" "";
            margin-left: -1em;
            position: absolute;
        }

        .markdown-body dd {
            position: relative;
        }
    </style>
    <script>
        // 初始化代码高亮
        document.addEventListener('DOMContentLoaded', (event) => {
            document.querySelectorAll('pre code').forEach((el) => {
                hljs.highlightElement(el);
            });

            // 初始化Mermaid图表
            if (typeof mermaid !== 'undefined') {
                mermaid.initialize({ startOnLoad: true, theme: 'default' });
                mermaid.init(undefined, '.language-mermaid');
            }

            // 处理数学公式
            if (typeof MathJax !== 'undefined') {
                MathJax.typeset();
            }

            // 使用Twemoji解析emoji
            if (typeof twemoji !== 'undefined') {
                twemoji.parse(document.body, {
                    base: 'https://twemoji.maxcdn.com/v/latest/',
                    ext: '.svg',
                    className: 'twemoji'
                });
            }
        });
    </script>
</head>

<body>
    <article class='markdown-body'>#CONTENT#</article>
</body>

</html>";
}

public class MarkdownUrl
{
    /// <summary>
    /// 完整的匹配文本
    /// </summary>
    public string FullMatch { get; set; }

    /// <summary>
    /// 是否是图片格式
    /// </summary>
    public bool IsImage { get; set; }

    /// <summary>
    /// 转换后的绝对路径
    /// </summary>
    public string Url { get; set; }

    /// <summary>
    /// 原始路径
    /// </summary>
    public string OriginalUrl { get; set; }

    /// <summary>
    /// 替代文本或标题
    /// </summary>
    public string AltText { get; set; }

    /// <summary>
    /// 在原文中的起始位置
    /// </summary>
    public int StartIndex { get; set; }

    /// <summary>
    /// 匹配文本的长度
    /// </summary>
    public int Length { get; set; }

    /// <summary>
    /// 是否是绝对路径
    /// </summary>
    public bool IsAbsolute { get; set; }
}